﻿using System;

namespace ST_CSharp_异步编程
{
    internal class Program
    {
        static async Task Main(string[] arges)
        {
            //FileWrite();
            //await FileWriteAsync();
            //await DownloadHtmlAsync(@"https://www.baidu.com", @"E:\a\1.txt");
            //Method1();
            //Method2();
            //await ReadAsync(1);
            //await Method3();

            //Console.WriteLine("A:" + Thread.CurrentThread.ManagedThreadId);
            //await Method4();
            //Console.WriteLine("D:" + Thread.CurrentThread.ManagedThreadId);

            //CancellationTokenSource cts = new CancellationTokenSource();
            //cts.CancelAfter(1000);
            //await DownloadAsync("https://www.baidu.com", 1, cts.Token);

            //await DownloadAsync2("https://www.baidu.com", cts.Token);

            //CancellationTokenSource cts2 = new CancellationTokenSource();
            //DownloadAsync2("https://www.baidu.com", cts2.Token);
            //cts2.Cancel();

            await WhenAllTest();
        }

        /// <summary>
        /// 普通方法
        /// </summary>
        private static void FileWrite()
        {
            string filename = @"E:\a\1.txt";
            File.WriteAllText(filename, "hello");
            File.ReadAllText(filename);
        }

        /// <summary>
        /// 异步方法
        /// </summary>
        /// <returns></returns>
        private static async Task FileWriteAsync()
        {
            string filename = @"E:\a\1.txt";
            await File.WriteAllTextAsync(filename, "hello");
            string s = await File.ReadAllTextAsync(filename);
            Console.WriteLine(s);
        }

        // 自己封装异步方法
        private static async Task<int> DownloadHtmlAsync(string url, string filename)
        {
            using (HttpClient httpClient = new HttpClient())
            {
                string html = await httpClient.GetStringAsync(url);
                await File.WriteAllTextAsync(filename, html);
                return html.Length;
            }
        }

        // 注意：尽量不要这么做，有死锁风险
        // 外层方法不支持异步时，可以通过.Result来调用异步方法
        private static void Method1()
        {
            Task<string> res = File.ReadAllTextAsync(@"E:\a\1.txt");
            string s = res.Result;
            Console.WriteLine(s);

            // 当异步方法无返回值时，可使用.Wait()方法
            File.WriteAllTextAsync(@"E:\a\1.txt", "hello").Wait();
        }

        // Lambda表达式中使用异步编程
        private static void Method2()
        {
            ThreadPool.QueueUserWorkItem(async (obj) =>
            {
                while (true)
                {
                    await File.WriteAllTextAsync(@"E:\a\1.txt", "hello");
                }
            });
            Console.ReadLine();
        }

        /// <summary>
        /// 没有Async的异步方法
        /// </summary>
        /// <returns></returns>
        private static Task<string> ReadAsync(int num)
        {
            if (num == 1)
            {
                return File.ReadAllTextAsync(@"E:\a\1.txt");
            }
            else if (num == 2)
            {
                return File.ReadAllTextAsync(@"E:\a\1.txt");
            }
            else
            {
                throw new ArgumentException();
            }
        }

        /// <summary>
        /// 异步方法中暂停
        /// 不能用Thread.Sleep()，因为他会阻塞线程
        /// 要用await Task.Delay()
        /// </summary>
        private static async Task Method3()
        {
            using (HttpClient http = new HttpClient())
            {
                string s = await http.GetStringAsync("https://www.baidu.com");
                Console.WriteLine("start");
                await Task.Delay(5000);
                Console.WriteLine(s);
            }
        }

        /// <summary>
        /// 线程切换
        /// </summary>
        /// <returns></returns>
        private static async Task Method4()
        {
            Console.WriteLine("B:" + Thread.CurrentThread.ManagedThreadId);
            await File.ReadAllTextAsync(@"E:\a\1.txt");
            Console.WriteLine("C:" + Thread.CurrentThread.ManagedThreadId);
        }


        /// <summary>
        /// 请求取消 CancellationToken
        /// </summary>
        /// <param name="url"></param>
        /// <param name="n"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private static async Task DownloadAsync(string url, int n, CancellationToken ct)
        {
            using (HttpClient http = new HttpClient())
            {
                for (int i = 0; i < n; i++)
                {
                    string html = await http.GetStringAsync(url);
                    Console.WriteLine(html.Substring(0,20));
                    if (ct.IsCancellationRequested)
                    {
                        Console.WriteLine("请求被取消");
                    }
                    ct.ThrowIfCancellationRequested();
                }
            }
        }

        /// <summary>
        /// 请求取消 CancellationToken
        /// </summary>
        /// <param name="url"></param>
        /// <param name="n"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private static async Task DownloadAsync2(string url, CancellationToken ct)
        {
            using (HttpClient http = new HttpClient())
            {
                var resp = await http.GetAsync(url, ct);
                string html = await resp.Content.ReadAsStringAsync();
                Console.WriteLine(html);
            }
        }

        private static async Task WhenAllTest()
        {
            Task<string> t1 = File.ReadAllTextAsync(@"E:\a\1.txt");
            Task<string> t2 = File.ReadAllTextAsync(@"E:\a\1.txt");
            Task<string> t3 = File.ReadAllTextAsync(@"E:\a\1.txt");
            string[] s = await Task.WhenAll(t1, t2, t3);
            Console.WriteLine(s[0]);
            Console.WriteLine(s[1]);
            Console.WriteLine(s[2]);
        }

        private static async Task WhenAllTest2()
        {
            string[] files = Directory.GetFiles(@"E:\a");
            Task<int>[] countTask = new Task<int>[files.Length];
            for (int i = 0; i < files.Length; i++)
            {
                countTask[i] = ReadCharsCount(files[i]);
            }
            int[] counts = await Task.WhenAll(countTask);
            int c = counts.Sum();
            Console.WriteLine(c);
        }

        private static async Task<int> ReadCharsCount(string filename)
        {
            string s = await File.ReadAllTextAsync(filename);
            return s.Length;
        }
    }
}